package com.jsoft.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsoft.constant.Constants;
import com.jsoft.controller.Code;
import com.jsoft.core.RedisTemplate;
import com.jsoft.dao.InformationDao;
import com.jsoft.entity.Information;
import com.jsoft.entity.LoginUser;
import com.jsoft.entity.User;
import com.jsoft.dao.UserDao;
import com.jsoft.exception.BusinessException;
import com.jsoft.exception.SystemException;
import com.jsoft.service.UserService;
import com.jsoft.util.Result;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static com.jsoft.controller.Code.GET_ERR;


/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2025-03-14 23:30:25
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 1.检查用户名是否在
     * 2.比较两者密码
     * 3.验证成功生成token
     * 4.从request提取ip等信息
     * 5.存入redis
     * 6.返回loginUser对象
     *
     * @param user 用户对象
     * @return 登录用户对象
     */
    @Override
    public LoginUser login(User user) {
        //查询用户名
        //分页查询用户

        List<User> usersList = userDao.queryByUsername(user.getUsername());


        if (usersList.size() == 0) {
            throw new BusinessException("用户名不存在", GET_ERR);
        }
        //如果用户存在获取对象
        User lUser = usersList.get(0);
        //转为MD5哈希码
        String passwordByMD5 = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
        if (!passwordByMD5.equals(lUser.getPassword())) {
            throw new BusinessException("密码错误", GET_ERR);
        }
        //生成token
        String token = UUID.randomUUID().toString();
        HttpServletRequest request =
                ((ServletRequestAttributes) Objects.
                        requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

        //获取到浏览器信息
        UserAgent userAgent = new UserAgent(request.getHeader("User-Agent"));
        //获取位置信息
        ResponseEntity<String> responseEntity =
                restTemplate.getForEntity("https://whois.pconline.com.cn/ip.jsp?ip=" + request.getRemoteAddr() + "&json=ture", String.class);
        String body = responseEntity.getBody();
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(lUser.getId());
        loginUser.setToken(token);
        loginUser.setLoginTime(new Date());
        loginUser.setIpaddr(request.getRemoteAddr());
        if (body != null) {
            loginUser.setLoginLocation(body.trim());
        } else {
            // 处理 body 为 null 的情况
            loginUser.setLoginLocation(""); // 否则设置默认值为空
        }
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOperatingSystem().getName());
        //设置密码为空
        lUser.setPassword(null);
        loginUser.setUser(lUser);
        //将封装好的LoginUser对象，放进redis中，key的格式是-》 token:用户名:UUID生成的token
        String tokenKey = Constants.TOKEN_PREFIX + lUser.getUsername() + ":" + token;
        redisTemplate.setObject(tokenKey, loginUser, Constants.TOKEN_TIME);
        return loginUser;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }

    /**
     * 通过用户名查询单条数据
     * 有用，勿动（syr）
     * @param username 用户名
     * @return 实例对象
     */
    @Override
    public List<User> queryByUsername(String username) {
        return this.userDao.queryByUsername(username);
    }

    /**
     * 通过手机号查询用户信息
     * 有用，勿动（syr）
     * @param phone 手机号
     * @return 实例对象集合
     */
    @Override
    public User selectByPhone(String phone){
        return this.userDao.selectByPhone(phone);
    }

    /**
     * 通过邮箱查询用户信息
     * 有用，勿动（syr）
     * @param email 邮箱
     * @return 实例对象集合
     */
    @Override
    public User selectByEmail(String email){
        return this.userDao.selectByEmail(email);
    }

    /**
     * 根据用户名更新手机号或邮箱
     * 有用，勿动（syr）
     * @param user 用户信息
     * @return 影响行数
     */
    @Override
    public int updateByUsername(User user){
        return this.userDao.updateByUsername(user);
    }

    /**
     * 分页查询
     *
     * @param user        筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    @Override
    public Page<User> queryByPage(User user, PageRequest pageRequest) {
        long total = this.userDao.count(user);
        return new PageImpl<>(this.userDao.queryAllByLimit(user, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        this.userDao.insert(user);
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }

    /**
     * 用户退出
     * 从请求头中取出token拼接成key
     * 删除对应的redis中的数据
     */
    @Override
    public void logout() {
        HttpServletRequest request =
                ((ServletRequestAttributes) Objects.
                        requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        //删除loginUser
        String token = request.getHeader(Constants.HEADER_AUTHORIZATION);
        String username = request.getHeader(Constants.HEADER_USERNAME);
        String tokenKey = Constants.TOKEN_PREFIX + username + ":" + token;
        //检查是否登陆过
        long result = redisTemplate.remove(tokenKey);
        if (result == 0L) {
            throw new BusinessException("用户未登录", GET_ERR);
        }

    }

    /**
     * 用户注册
     * 1.先判断邮箱和手机号不能同时写
     * 2.判断电话邮箱是否为空
     * 3.再判断电话邮箱是否被注册过
     * 4.同时向user表插入信息
     *
     * @param user 注册用户信息
     */
    @Override
    public void register(User user) {
        String username;
        //判断同时生成用户名
        if (user.getPhone() != null && user.getEmail() != null) {
            throw new BusinessException("邮箱和手机号不能同时写", Code.GET_ERR);
        } else if (user.getPhone() != null) {
            List<User> users = userDao.queryByPhone(user.getPhone());
            if (users.size() > 0) {
                throw new BusinessException("电话号已被注册", Code.GET_ERR);
            } else {
                username = Constants.USERNAME_PREFIX + user.getPhone();//生成用户名-》user_139xxxxxxxx;
            }
        } else if (user.getEmail() != null) {
            List<User> users = userDao.queryByEmail(user.getEmail());
            if (users.size() > 0) {
                throw new BusinessException("邮箱已被注册", Code.GET_ERR);
            } else {
                username = Constants.USERNAME_PREFIX + user.getEmail();//生成用户名-》user_xxx@qq.com;
            }
        } else {
            throw new BusinessException("邮箱和手机号不能为空", GET_ERR);
        }
        //插入用户数据
        user.setUsername(username);
        //password MD5加密
        String passwordByMD5 = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
        user.setPassword(passwordByMD5);
        user.setUpdateTime(new Date());
        user.setStatus(0);
        userDao.insert(user);
    }

    /**
     * 通过电话号查用户
     *
     * @param phone 电话号
     * @return 用户
     */
    @Override
    public User queryByPhone(String phone) {
        User user = null;
        List<User> usersList = userDao.queryByPhone(phone);
        if (usersList.size() > 0) {
            user = usersList.get(0);
        } else {
            throw new SystemException("电话号不存在", GET_ERR);
        }
        return user;
    }

    /**
     *
     * 通过电话号更新密码
     *
     * @param phone 电话
     * @param password 密码
     */
    @Override
    public void updateByPhone(String phone, String password) {
        if(password.length()>16 || password.length()<6){
            throw new BusinessException("密码长度不符合规范", GET_ERR);
        }
        String passwordByMD5 = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
        Date updateTime = new Date();
        userDao.updateByPhone(phone,passwordByMD5,updateTime);
    }
}